/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#include "pch.h"
#include <journal/common/storage_service.h>
#include <baja\stream\storage_file.h>
#include <baja\stream\storage_folder.h>

namespace journal { namespace services { namespace storage {

namespace s = baja::storage;

storage_service::storage_service()
{
}

std::shared_ptr<storage_service> storage_service::create()
{
    std::shared_ptr<storage_service> returnValue = std::make_shared<storage_service>();
    return returnValue;
}

void storage_service::onBeforeSettingChange(const b::wchar* fullName)
{
}

void storage_service::onAfterSettingChange(const b::wchar* fullName)
{
}

void storage_service::copyTemplateNotebook(const std::wstring& appDataFolder, const std::wstring& dbFileName)
{
    baja::win32::details::safe_handle allDoneEvent(::CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS));
    size_t count;
    std::shared_ptr<s::istorage_file> dbFile = s::storage_file::create();
    std::shared_ptr<s::istorage_folder> folder = s::storage_folder::create();
    dbFile->initializeAsync(dbFileName, [&](bool fileExists) {
        if (fileExists)
        {
            // database exists. 
            SetEvent(allDoneEvent.get());
        }
        else
        {
            // database file doesn't exist.  Copy the template.
            dbFile = nullptr;
            Windows::Storage::StorageFolder^ appInstallFolder = Windows::ApplicationModel::Package::Current->InstalledLocation;

            std::wstring appFolderName = std::wstring( appInstallFolder->Path->Data(), appInstallFolder->Path->Length()) + L"\\";
            std::wstring databaseTemplateFolder = appFolderName + L"res\\helpfiles";
            
            folder->initializeAsync(databaseTemplateFolder, [&](bool folderExists) {
                if (!folderExists) 
                {
                    // helpfile directory doesn't exist
                    SetEvent(allDoneEvent.get());
                }
                else 
                {
                    folder->getFilesAsync([&](bool result, const std::vector<std::shared_ptr<s::istorage_file>>& files) {
                        if (!result)
                        {
                            // helpfile notebook doesn't exsit
                            SetEvent(allDoneEvent.get());
                        }
                        else
                        {
                            count = files.size();
                            for (auto file : files) 
                            {
                                std::wstring newFileName = appDataFolder + file->fileName();
                                file->copyToAsync(newFileName, [&](bool sucess, std::shared_ptr<s::istorage_file> file) {
                                    if (InterlockedDecrement(&count) == 0)
                                        SetEvent(allDoneEvent.get());
                                });
                            }
                        }
                    });
                }
                
            });
        }
    });
    WaitForSingleObjectEx(allDoneEvent.get(), INFINITE, FALSE);
}

void storage_service::initialize()
{
    Windows::Storage::StorageFolder^ appDataFolder = Windows::Storage::ApplicationData::Current->LocalFolder;

    std::wstring workingFolderName = std::wstring( appDataFolder->Path->Data(), appDataFolder->Path->Length() ) + L"\\";
    std::wstring dbFileName = workingFolderName + L"austin.db";

    // Do not copy the template notebook until we have the proper help files
    // copyTemplateNotebook(workingFolderName, dbFileName);

    std::shared_ptr<s::iengine> se = s::createEngine();
    se->createInstance(workingFolderName);
    se->beginSession();
    se->openDatabase(dbFileName);

    _engine = se;
}

std::shared_ptr<baja::storage::iengine> storage_service::engine()
{
    return _engine;
}

std::shared_ptr<istorage_service> journal::services::storage::createStorageService()
{
    std::shared_ptr<storage_service> returnValue;
    returnValue = storage_service::create();
    returnValue->initialize();
    return std::dynamic_pointer_cast<istorage_service>(returnValue);
}

}}} // journal::services::storage
